package com.smart.community.region.service.impl;

import com.smart.community.region.service.ICacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 缓存服务实现类
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 */
@Slf4j
@Service
public class CacheServiceImpl implements ICacheService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 缓存键前缀
    private static final String TEMPLATE_DATA_PREFIX = "template:data:";
    private static final String VALIDATION_RESULT_PREFIX = "template:validation:";
    private static final String IMPORT_PROGRESS_PREFIX = "template:progress:";

    @Override
    public void cacheTemplateData(String fileId, Map<String, List<Map<String, Object>>> data, long expireMinutes) {
        String key = TEMPLATE_DATA_PREFIX + fileId;
        try {
            redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(expireMinutes));
            log.info("模板数据缓存成功，文件ID：{}，过期时间：{}分钟", fileId, expireMinutes);
        } catch (Exception e) {
            log.error("模板数据缓存失败，文件ID：{}", fileId, e);
            throw new RuntimeException("缓存模板数据失败：" + e.getMessage());
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, List<Map<String, Object>>> getCachedTemplateData(String fileId) {
        String key = TEMPLATE_DATA_PREFIX + fileId;
        try {
            Object data = redisTemplate.opsForValue().get(key);
            if (data != null) {
                log.info("获取缓存的模板数据成功，文件ID：{}", fileId);
                return (Map<String, List<Map<String, Object>>>) data;
            } else {
                log.warn("缓存的模板数据不存在，文件ID：{}", fileId);
                return null;
            }
        } catch (Exception e) {
            log.error("获取缓存的模板数据失败，文件ID：{}", fileId, e);
            throw new RuntimeException("获取缓存数据失败：" + e.getMessage());
        }
    }

    @Override
    public void cacheValidationResult(String fileId, Object validationResult, long expireMinutes) {
        String key = VALIDATION_RESULT_PREFIX + fileId;
        try {
            redisTemplate.opsForValue().set(key, validationResult, Duration.ofMinutes(expireMinutes));
            log.info("验证结果缓存成功，文件ID：{}，过期时间：{}分钟", fileId, expireMinutes);
        } catch (Exception e) {
            log.error("验证结果缓存失败，文件ID：{}", fileId, e);
            throw new RuntimeException("缓存验证结果失败：" + e.getMessage());
        }
    }

    @Override
    public Object getCachedValidationResult(String fileId) {
        String key = VALIDATION_RESULT_PREFIX + fileId;
        try {
            Object result = redisTemplate.opsForValue().get(key);
            if (result != null) {
                log.info("获取缓存的验证结果成功，文件ID：{}", fileId);
                return result;
            } else {
                log.warn("缓存的验证结果不存在，文件ID：{}", fileId);
                return null;
            }
        } catch (Exception e) {
            log.error("获取缓存的验证结果失败，文件ID：{}", fileId, e);
            throw new RuntimeException("获取缓存验证结果失败：" + e.getMessage());
        }
    }

    @Override
    public void cacheImportProgress(String taskId, Object progress, long expireMinutes) {
        String key = IMPORT_PROGRESS_PREFIX + taskId;
        try {
            redisTemplate.opsForValue().set(key, progress, Duration.ofMinutes(expireMinutes));
            log.info("导入进度缓存成功，任务ID：{}，过期时间：{}分钟", taskId, expireMinutes);
        } catch (Exception e) {
            log.error("导入进度缓存失败，任务ID：{}", taskId, e);
            throw new RuntimeException("缓存导入进度失败：" + e.getMessage());
        }
    }

    @Override
    public Object getCachedImportProgress(String taskId) {
        String key = IMPORT_PROGRESS_PREFIX + taskId;
        try {
            Object progress = redisTemplate.opsForValue().get(key);
            if (progress != null) {
                log.info("获取缓存的导入进度成功，任务ID：{}", taskId);
                return progress;
            } else {
                log.warn("缓存的导入进度不存在，任务ID：{}", taskId);
                return null;
            }
        } catch (Exception e) {
            log.error("获取缓存的导入进度失败，任务ID：{}", taskId, e);
            throw new RuntimeException("获取缓存导入进度失败：" + e.getMessage());
        }
    }

    @Override
    public void updateImportProgress(String taskId, int progress, String currentStep, 
                                   int processedCount, int totalCount, int errorCount) {
        String key = IMPORT_PROGRESS_PREFIX + taskId;
        try {
            // 创建进度对象
            ImportProgress progressObj = new ImportProgress();
            progressObj.setTaskId(taskId);
            progressObj.setProgress(progress);
            progressObj.setCurrentStep(currentStep);
            progressObj.setProcessedCount(processedCount);
            progressObj.setTotalCount(totalCount);
            progressObj.setErrorCount(errorCount);
            progressObj.setUpdateTime(System.currentTimeMillis());

            // 更新缓存
            redisTemplate.opsForValue().set(key, progressObj, Duration.ofHours(1));
            log.info("更新导入进度成功，任务ID：{}，进度：{}%", taskId, progress);
        } catch (Exception e) {
            log.error("更新导入进度失败，任务ID：{}", taskId, e);
            throw new RuntimeException("更新导入进度失败：" + e.getMessage());
        }
    }

    @Override
    public void clearExpiredCache() {
        try {
            // 清理过期的模板数据缓存
            Set<String> templateKeys = redisTemplate.keys(TEMPLATE_DATA_PREFIX + "*");
            if (templateKeys != null && !templateKeys.isEmpty()) {
                for (String key : templateKeys) {
                    Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
                    if (ttl != null && ttl <= 0) {
                        redisTemplate.delete(key);
                        log.info("清理过期模板数据缓存：{}", key);
                    }
                }
            }

            // 清理过期的验证结果缓存
            Set<String> validationKeys = redisTemplate.keys(VALIDATION_RESULT_PREFIX + "*");
            if (validationKeys != null && !validationKeys.isEmpty()) {
                for (String key : validationKeys) {
                    Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
                    if (ttl != null && ttl <= 0) {
                        redisTemplate.delete(key);
                        log.info("清理过期验证结果缓存：{}", key);
                    }
                }
            }

            // 清理过期的导入进度缓存
            Set<String> progressKeys = redisTemplate.keys(IMPORT_PROGRESS_PREFIX + "*");
            if (progressKeys != null && !progressKeys.isEmpty()) {
                for (String key : progressKeys) {
                    Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
                    if (ttl != null && ttl <= 0) {
                        redisTemplate.delete(key);
                        log.info("清理过期导入进度缓存：{}", key);
                    }
                }
            }

            log.info("缓存清理完成");
        } catch (Exception e) {
            log.error("清理过期缓存失败", e);
        }
    }

    @Override
    public Map<String, Object> getCacheStatistics() {
        Map<String, Object> statistics = new HashMap<>();
        try {
            // 统计模板数据缓存
            Set<String> templateKeys = redisTemplate.keys(TEMPLATE_DATA_PREFIX + "*");
            statistics.put("templateDataCount", templateKeys != null ? templateKeys.size() : 0);

            // 统计验证结果缓存
            Set<String> validationKeys = redisTemplate.keys(VALIDATION_RESULT_PREFIX + "*");
            statistics.put("validationResultCount", validationKeys != null ? validationKeys.size() : 0);

            // 统计导入进度缓存
            Set<String> progressKeys = redisTemplate.keys(IMPORT_PROGRESS_PREFIX + "*");
            statistics.put("importProgressCount", progressKeys != null ? progressKeys.size() : 0);

            // 统计总缓存数量
            int totalCount = (int) statistics.get("templateDataCount") + 
                           (int) statistics.get("validationResultCount") + 
                           (int) statistics.get("importProgressCount");
            statistics.put("totalCount", totalCount);

            log.info("获取缓存统计信息成功：{}", statistics);
        } catch (Exception e) {
            log.error("获取缓存统计信息失败", e);
            statistics.put("error", e.getMessage());
        }
        return statistics;
    }

    @Override
    public void deleteCache(String key) {
        try {
            Boolean result = redisTemplate.delete(key);
            if (Boolean.TRUE.equals(result)) {
                log.info("删除缓存成功，键：{}", key);
            } else {
                log.warn("删除缓存失败，键不存在：{}", key);
            }
        } catch (Exception e) {
            log.error("删除缓存失败，键：{}", key, e);
            throw new RuntimeException("删除缓存失败：" + e.getMessage());
        }
    }

    @Override
    public boolean exists(String key) {
        try {
            Boolean result = redisTemplate.hasKey(key);
            return Boolean.TRUE.equals(result);
        } catch (Exception e) {
            log.error("检查缓存是否存在失败，键：{}", key, e);
            return false;
        }
    }

    @Override
    public void expire(String key, long expireMinutes) {
        try {
            Boolean result = redisTemplate.expire(key, Duration.ofMinutes(expireMinutes));
            if (Boolean.TRUE.equals(result)) {
                log.info("设置缓存过期时间成功，键：{}，过期时间：{}分钟", key, expireMinutes);
            } else {
                log.warn("设置缓存过期时间失败，键不存在：{}", key);
            }
        } catch (Exception e) {
            log.error("设置缓存过期时间失败，键：{}", key, e);
            throw new RuntimeException("设置缓存过期时间失败：" + e.getMessage());
        }
    }

    @Override
    public long getTtl(String key) {
        try {
            Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            return ttl != null ? ttl : -1;
        } catch (Exception e) {
            log.error("获取缓存剩余时间失败，键：{}", key, e);
            return -1;
        }
    }

    @Override
    public void cacheTemplateBytes(String key, byte[] data, long expireMinutes) {
        try {
            redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(expireMinutes));
            log.info("模板字节数组缓存成功，键：{}，过期时间：{}分钟", key, expireMinutes);
        } catch (Exception e) {
            log.error("模板字节数组缓存失败，键：{}", key, e);
            throw new RuntimeException("缓存模板字节数组失败：" + e.getMessage());
        }
    }

    @Override
    public byte[] getCachedTemplateBytes(String key) {
        try {
            Object value = redisTemplate.opsForValue().get(key);
            if (value instanceof byte[]) {
                log.debug("从缓存获取模板字节数组成功，键：{}", key);
                return (byte[]) value;
            }
            log.debug("缓存中未找到模板字节数组，键：{}", key);
            return null;
        } catch (Exception e) {
            log.error("获取缓存的模板字节数组失败，键：{}", key, e);
            return null;
        }
    }

    /**
     * 导入进度内部类
     */
    public static class ImportProgress {
        private String taskId;
        private int progress;
        private String currentStep;
        private int processedCount;
        private int totalCount;
        private int errorCount;
        private long updateTime;

        // Getters and Setters
        public String getTaskId() {
            return taskId;
        }

        public void setTaskId(String taskId) {
            this.taskId = taskId;
        }

        public int getProgress() {
            return progress;
        }

        public void setProgress(int progress) {
            this.progress = progress;
        }

        public String getCurrentStep() {
            return currentStep;
        }

        public void setCurrentStep(String currentStep) {
            this.currentStep = currentStep;
        }

        public int getProcessedCount() {
            return processedCount;
        }

        public void setProcessedCount(int processedCount) {
            this.processedCount = processedCount;
        }

        public int getTotalCount() {
            return totalCount;
        }

        public void setTotalCount(int totalCount) {
            this.totalCount = totalCount;
        }

        public int getErrorCount() {
            return errorCount;
        }

        public void setErrorCount(int errorCount) {
            this.errorCount = errorCount;
        }

        public long getUpdateTime() {
            return updateTime;
        }

        public void setUpdateTime(long updateTime) {
            this.updateTime = updateTime;
        }
    }
}
